﻿// <copyright file="CpFile.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// This class represents a CP file in Microsoft Application Virtualization (App-V).
    /// </summary>
    public class CpFile : IDisposable
    {
        /// <summary>
        /// The header for the CP file.
        /// </summary>
        private CpFileHeader header;

        /// <summary>
        /// Section 0x00 - mapping data for VFS entries
        /// </summary>
        private VfsMappingList vfsMappingList;

        /// <summary>
        /// Section 0x01 - virtual registry data
        /// </summary>
        private VirtualRegistryEntryList virtualRegistryData;

        /// <summary>
        /// Section 0x05 - font data
        /// </summary>
        private FontPathEntryList fontPathList;

        /// <summary>
        /// Section 0x06 - list of VFS source paths
        /// </summary>
        private VfsSourcePathList vfsSourcePathList;

        /// <summary>
        /// Section 0x07 - NT object exclusion list
        /// </summary>
        private NtObjectList excludedObjectsList;

        /// <summary>
        /// Section 0x09 - virtual registry data (machine)
        /// </summary>
        private MachineVirtualRegistryData virtualMachineRegistryData;

        /// <summary>
        /// Section 0x0A - virtual registry data (user)
        /// </summary>
        private VirtualRegistryEntryList virtualUserRegistryData;

        /// <summary>
        /// Section 0x0B - unique ID copy
        /// </summary>
        private UniqueIDCopy uniqueIdCopySection;

        /// <summary>
        /// A list of the data sections from the CP file.
        /// </summary>
        private List<DataSection> dataSections;

        /// <summary>
        /// A stream around the CP file.
        /// </summary>
        private System.IO.FileStream inputStream;

        /// <summary>
        /// A binary reader for the CP file stream.
        /// </summary>
        private System.IO.BinaryReader reader;

        /// <summary>
        /// Initializes a new instance of the CpFile class.
        /// </summary>
        /// <param name="filePath">The full path of an SFT file.</param>
        public CpFile(string filePath)
        {
            this.dataSections = new List<DataSection>();

            if (System.IO.File.Exists(filePath))
            {
                this.inputStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
                this.reader = new System.IO.BinaryReader(this.inputStream, Encoding.ASCII);

                if (this.reader.PeekChar() != -1)
                {
                    this.header = new CpFileHeader(this.reader);

                    // Read the data sections.
                    long offset = this.header.FirstSectionOffset;
                    while (offset != 0xFFFFFFFF)
                    {
                        this.reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin);
                        DataSection ds = new DataSection(this.reader);
                        this.dataSections.Add(ds);
                        offset = ds.NextSectionOffset;

                        switch (ds.SectionType)
                        {
                            case SectionIdentifierCode.UniqueIdCopy:
                                this.uniqueIdCopySection = new UniqueIDCopy(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.NtObjectExclusionList:
                                this.excludedObjectsList = new NtObjectList(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.MappingDataForVfsEntries:
                                this.vfsMappingList = new VfsMappingList(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.ListOfVfsSourcePaths:
                                this.vfsSourcePathList = new VfsSourcePathList(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.VirtualRegistryData:
                                this.virtualRegistryData = new VirtualRegistryEntryList(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.VirtualRegistryDataUser:
                                this.virtualUserRegistryData = new VirtualRegistryEntryList(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.VirtualRegistryDataMachine:
                                this.virtualMachineRegistryData = new MachineVirtualRegistryData(ds.GetSectionData());
                                break;
                            case SectionIdentifierCode.Fonts:
                                this.fontPathList = new FontPathEntryList(ds.GetSectionData());
                                break;                                
                            default:
                                // Unhandled section type.
                                break;
                        }                        
                    }
                }

                this.reader.Close();
                this.inputStream.Close();
                this.inputStream.Dispose();
            }
            else
            {
                throw new System.IO.FileNotFoundException("The specified file could not be found.", filePath);
            }
        }

        /// <summary>
        /// Gets the header for the CP file.
        /// </summary>
        public CpFileHeader Header
        {
            get { return this.header; }
        }

        /// <summary>
        /// Section 0x01 - virtual registry data
        /// </summary>
        public VirtualRegistryEntryList VirtualRegistry
        {
            get { return this.virtualRegistryData; }
        }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing,
        /// or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.reader.Close();
            this.inputStream.Close();
            this.inputStream.Dispose();
        }

        #endregion
    }
}
